Macアプリ、Obj-CでのNSDictionary略記法のダークなタイミング


概要

NSDictionaryの略記法使うと、理由不明のエラーが出るケース。

ずーっと自分のライブラリ疑ってたんだけど、違った。

下記ケースで、NSDictionaryの生成略記法 @{} での辞書生成が悪さをする。

ちなみにMac版アプリだけで発生を確認している。

iOS用だと、実機/シミュレータともに発生していない。



環境

Xcode 4.6.2

Mac OS 10.8.3

ARC:あり

Mac用アプリ



症状

IMPを指定してのメソッド実行で、そのメソッド内で

NSDictionary * dict = @{@"key":@"value"};


とすると、生成時は死なないが、メソッドを抜ける瞬間に


EXEC_BAD_ACCESS(code=12,address=0x0)


が発生する。

発生確率は10/100回、10%くらい。Jenkins見てる限りはそんな感じ。

環境差とかはわからん。


サンプルコード

#import "AppDelegate.h"


@implementation AppDelegate {

    SEL m_receiver;

}


- (void)applicationDidFinishLaunching:(NSNotification *)aNotification

{

    m_receiver = @selector(receiver:);

    

    // Insert code here to initialize your application

    IMP func = [self methodForSelector:m_receiver];

    (* func)(self, m_receiver, aNotification);

}


- (void) receiver:(NSNotification * )notif {

    NSLog(@"hereComes %@", notif);

    NSDictionary * dict = @{@"key":@"val"};//←

}


@end


←のあるラインで、この行を通過後、

(* func)(self, m_receiver, aNotification);

この行を抜けるタイミングでエラーになる。



サンプルプロジェクト

githubに上げといた。

https://github.com/sassembla/DummyProject


100回Jenkinsさんでまわして発生するか試してみた条件など

・ARCをオフにすると発生しない

・略記法@{}ではなく、通常記法だと発生しない


・辞書の内容を空にすると発生しない

NSDictionary * dict = @{}; だと、発生しなかった。


・switch文に入れ、通過しないcaseの中にあっても発生した

ぶっちゃけ原因追及に時間がかかった理由はこれで、

switch文、しかもその時点では内容が存在するcaseを通過しない、という条件にも関わらず、発生している。


switch文を加えた、下記コードでも問題が発生する。

- (void) receiver:(NSNotification * )notif {

    NSLog(@"hereComes %@", notif);

    

    int a = 0;

    

    switch (a) {

        case 0:{

            break;

        }

        case -1:{

            NSDictionary * dict = @{@"key":@"val"};//←

            break;

        }

            

        default:

            break;

    }

}


aが0なのは自明だし、switch文で0に飛び込むので、まーなんも起こらねーだろと思ったら、発生した。

略記法の内容生成自体はswitch文生成と一緒に行われてるんだろうな。

実際にallocするかどうかは別として。



発生確率を上げる方法

特に思いついていないが、複数、辞書の初期化コードを書くとかしても、発生率に変化は無かった、、とおもう。たぶん。


誰かのハマりの助けになれたらと思うが。

なんかあったらgithubのIssueでもください。

スクリーンショット 2013-05-14 17.01.32.png